如何使用 Nvidia NeMo 微调 Riva NMT 多语言模型#

本教程将引导您了解如何使用 Nvidia NeMo 微调 Riva NMT 多语言模型。

NVIDIA Riva 概述#

NVIDIA Riva 是一个 GPU 加速的 SDK,用于构建针对您的用例定制并提供实时性能的语音 AI 应用程序。
Riva 提供了一系列丰富的语音和自然语言理解服务,例如

  • 自动语音识别 (ASR)

  • 文本到语音合成 (TTS)

  • 神经机器翻译 (NMT)

  • 自然语言处理 (NLP) 服务集合,例如命名实体识别 (NER)、标点符号和意图分类。

在本教程中,我们将使用 Nvidia NeMo 微调 Riva NMT 多语言模型。
要了解 Riva NMT API 的基础知识,请参阅 Riva NMT 教程 中的“如何将 Riva NMT API 与开箱即用模型一起执行语言翻译?”教程。

有关 Riva 的更多信息,请参阅 Riva 开发者文档
有关 Riva NMT 的更多信息,请参阅 Riva NMT 文档

NVIDIA NeMo 概述#

NVIDIA NeMo 是一个用于构建新型先进的对话式 AI 模型的工具包。 NeMo 针对自动语音识别 (ASR)、自然语言处理 (NLP) 和文本到语音 (TTS) 模型有单独的集合。 每个集合都包含预构建的模块,其中包括在您的数据上进行训练所需的一切。 每个模块都可以轻松地进行自定义、扩展和组合,以创建新的对话式 AI 模型架构。

有关 NeMo 的更多信息,请参阅 NeMo 产品页面文档。 开源 NeMo 存储库可以在此处找到。

使用 NVIDIA NeMo 微调 Riva NMT 多语言模型#

在本教程中,我们将基于 Scielo 英语-西班牙语-葡萄牙语数据集 微调 Riva NMT 多语言 Any-to-En 模型。

本教程仅涵盖微调 NMT 多语言模型。 微调多语言模型是一项相对更具挑战性的任务(例如选择涵盖多种语言的平衡数据集)。 在此阶段,多语言微调仅在使用特定的 NeMo 和 Pytorch lightning 版本 (PTL<2.0) 时才受支持。 我们建议您使用此处共享的特定 NeMo 分支。

此处的微调过程可以分为以下步骤

  1. 数据下载。

  2. 数据预处理。

  3. 使用 NeMo 微调 NMT 模型。

  4. 使用 NeMo 评估微调后的 NMT 模型。

  5. 导出 NeMo 模型

  6. 在 Riva Speech Skills 服务器上部署微调后的 NeMo NMT 模型。

让我们详细了解每个步骤。

要求和设置#

本教程需要在 NeMo docker 容器内运行。 如果您不是通过 NeMo docker 容器运行本教程,请参阅 Riva NMT 教程 以开始使用。

在开始要求和设置之前,让我们在此处为我们的工作创建一个基本目录。

import os
base_dir = "NMTFinetuning"
!mkdir $base_dir
base_dir=os.path.abspath("NMTFinetuning")
  1. 克隆 NeMo github 存储库

NeMoBranch = "r1.19.0"
!git clone -b $NeMoBranch https://github.com/bpritam14/NeMo.git $base_dir/NeMo
!apt-get update && apt-get install -y libsndfile1 ffmpeg
%cd $base_dir/NeMo
!./reinstall.sh
%cd ..

检查 CUDA 安装。

import torch
torch.cuda.is_available()
警告:您可能需要安装 `apex`。
!git clone https://github.com/NVIDIA/apex.git
%cd apex
!git checkout 57057e2fcf1c084c0fcc818f55c0ff6ea1b24ae2
!pip install -v --disable-pip-version-check --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" --global-option="--fast_layer_norm" --global-option="--distributed_adam" --global-option="--deprecated_fused_adam" ./
%cd ..
  1. Riva 快速入门指南 安装 nemo2riva 库。

# Install the `nemo2riva` library
!python3 -m pip install nemo2riva
  1. 安装本教程所需的其他库。

!python3 -m pip install scikit-learn

步骤 1. 数据下载#

让我们下载 Scielo 英语-西班牙语-葡萄牙语数据集。 具体来说,我们将下载 Moses 版本的 数据集,该数据集由 3 个文件组成,en_pt_es.enen_pt_es.pten_pt_es.esen_pt_es.en 文件中每个以换行符分隔的条目都是 en_pt_es.esen_pt_es.pt 文件中相应条目的翻译,反之亦然。

data_dir = base_dir + "/data"
!mkdir $data_dir

# Download the Scielo dataset
!wget -P $data_dir https://figshare.com/ndownloader/files/14019293
# Untar the downloaded the Scielo dataset
!tar -xvf $data_dir/14019293 -C $data_dir

步骤 2. 数据预处理#

数据预处理包括多个步骤,以提高数据集的质量。 NeMo 文档 提供了有关 NMT 的 8 步数据预处理的详细说明。 NeMo 还提供了一个 jupyter notebook,它以编程方式引导用户完成不同的预处理步骤。 请注意,根据数据集的不同,可以跳过部分或全部预处理步骤。

为了简化 Riva NMT 程序中的微调过程,我们通过 NeMo 存储库提供了 3 个预处理脚本。 这些脚本的输入将是 2 个并行语料库(即源语言和目标语言)数据文件。 在本教程中,我们使用 Moses 版本的 Scielo 数据集,该数据集直接为我们提供了源数据 (en_pt_es.en) 和目标数据 (en_pt_es.es) 文件。 如果数据集未直接提供这些文件,那么我们首先需要从数据集中生成这两个文件,然后再使用预处理脚本。

以下脚本公开了许多参数,其中最常见的是

  • input-src:包含源语言文本的输入文件的路径。

  • input-tgt:包含目标语言文本的输入文件的路径。

  • output-src:要保存归一化和分词的源语言数据的文件路径。

  • output-tgt:要保存归一化和分词的目标语言数据的文件路径。

  • source-lang:源语言的语言代码。

  • target-lang:目标语言的语言代码。

特定于脚本的其他内容将在各自的部分中介绍。

a. 语言过滤#

语言过滤预处理脚本用于使用 Fasttext 语言识别模型 验证机器翻译数据集中的语言。 如果脚本用于并行语料库,它将验证源语言和目标语言。 过滤后的数据存储到由 output_srcoutput-tgt 指定的文件中,删除的行放入由 removed_srcremoved-tgt 指定的文件中。 如果无法检测到语言(例如,日期),则删除该行。

此脚本公开了许多参数,其中最常见的是

  • removed-src:要保存来自源语言的丢弃数据的文件路径。

  • removed-tgt:要保存来自目标语言的丢弃数据的文件路径。

  • fasttext-model:Fasttext 模型的路径。 说明和下载链接在此处

# Let us first download the fasttext model.
!wget https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin -O $data_dir/lid.176.bin
# Running the language filtering preprocessing script. 
!python $base_dir/NeMo/scripts/neural_machine_translation/filter_langs_nmt.py \
    --input-src $data_dir/en_pt_es.en \
    --input-tgt $data_dir/en_pt_es.es \
    --output-src $data_dir/en_es_preprocessed1.en \
    --output-tgt $data_dir/en_es_preprocessed1.es \
    --removed-src $data_dir/en_es_garbage1.en \
    --removed-tgt $data_dir/en_es_garbage1.es \
    --source-lang en \
    --target-lang es \
    --fasttext-model $data_dir/lid.176.bin

# Run similarly for en and pt too (or other languages as needed)
!python $base_dir/NeMo/scripts/neural_machine_translation/filter_langs_nmt.py \
    --input-src $data_dir/en_pt_es.en \
    --input-tgt $data_dir/en_pt_es.pt \
    --output-src $data_dir/en_pt_preprocessed1.en \
    --output-tgt $data_dir/en_pt_preprocessed1.pt \
    --removed-src $data_dir/en_pt_garbage1.en \
    --removed-tgt $data_dir/en_pt_garbage1.pt \
    --source-lang en \
    --target-lang pt \
    --fasttext-model $data_dir/lid.176.bin

b. 长度过滤#

长度过滤脚本是一个多进程脚本,用于过滤并行语料库以删除长度小于最小长度或大于最大长度的句子。 它还根据源句和目标句之间的长度比率进行过滤。

此脚本公开了许多参数,其中最常见的是

  • removed-src:要保存来自源语言的丢弃数据的文件路径。

  • min-length:最小序列长度。

  • max-length:最大序列长度。

  • ratio:源句子长度与目标句子长度的比率。

# Running the length filtering preprocessing script.
!python $base_dir/NeMo/scripts/neural_machine_translation/length_ratio_filter.py \
    --input-src $data_dir/en_es_preprocessed1.en \
    --input-tgt $data_dir/en_es_preprocessed1.es \
    --output-src $data_dir/en_es_preprocessed2.en \
    --output-tgt $data_dir/en_es_preprocessed2.es \
    --removed-src $data_dir/en_es_garbage2.en \
    --removed-tgt $data_dir/en_es_garbage2.es \
    --min-length 1 \
    --max-length 512 \
    --ratio 1.3

# Run similarly for en and pt too (or other languages as needed)
!python $base_dir/NeMo/scripts/neural_machine_translation/length_ratio_filter.py \
    --input-src $data_dir/en_pt_preprocessed1.en \
    --input-tgt $data_dir/en_pt_preprocessed1.pt \
    --output-src $data_dir/en_pt_preprocessed2.en \
    --output-tgt $data_dir/en_pt_preprocessed2.pt \
    --removed-src $data_dir/en_pt_garbage2.en \
    --removed-tgt $data_dir/en_pt_garbage2.pt \
    --min-length 1 \
    --max-length 512 \
    --ratio 1.3

分词和归一化#

分词和归一化脚本对输入源语言和目标语言数据进行归一化和分词。

!python $base_dir/NeMo/scripts/neural_machine_translation/preprocess_tokenization_normalization.py \
    --input-src $data_dir/en_es_preprocessed2.en \
    --input-tgt $data_dir/en_es_preprocessed2.es \
    --output-src $data_dir/en_es_final.en \
    --output-tgt $data_dir/en_es_final.es \
    --source-lang en \
    --target-lang es

!python $base_dir/NeMo/scripts/neural_machine_translation/preprocess_tokenization_normalization.py \
    --input-src $data_dir/en_pt_preprocessed2.en \
    --input-tgt $data_dir/en_pt_preprocessed2.pt \
    --output-src $data_dir/en_pt_final.en \
    --output-tgt $data_dir/en_pt_final.pt \
    --source-lang en \
    --target-lang pt

训练、开发和验证集拆分#

对于数据预处理的最后一步,我们将把数据集拆分为训练集、开发集和验证集。
这是一个可选步骤 - 许多数据集已经带有训练集、开发集和验证集拆分,但我们在本教程中使用的 Scielo 数据集没有这样的拆分。 因此,我们将使用 scikit-learn 来拆分数据集。

"""
    Read all final files into memory
"""
def read_data_from_file(filename):
    with open(filename) as f:
        lines = f.readlines()
    return lines
    
en_es_final_en = read_data_from_file(data_dir + "/en_es_final.en")
en_es_final_es = read_data_from_file(data_dir + "/en_es_final.es")
en_pt_final_en = read_data_from_file(data_dir + "/en_pt_final.en")
en_pt_final_pt = read_data_from_file(data_dir + "/en_pt_final.pt")

print("Number of entries in the final Scielo English-Spanish dataset = ", len(en_es_final_en))
print("Number of entries in the final Scielo English-Portugese dataset = ", len(en_pt_final_en))
"""
    Split the dataset into train, test and val using scikit learn's train_test_split
"""
from sklearn.model_selection import train_test_split

test_ratio = 0.10
validation_ratio = 0.11 # (10% of remaining)
train_ratio = 1.0 - validation_ratio - test_ratio

en_es_final_en_trainval, en_es_final_en_test, en_es_final_es_trainval, en_es_final_es_test = \
    train_test_split(en_es_final_en, en_es_final_es, test_size=test_ratio, random_state=1)

en_es_final_en_train, en_es_final_en_val, en_es_final_es_train, en_es_final_es_val = \
    train_test_split(en_es_final_en_trainval, en_es_final_es_trainval, test_size=validation_ratio, random_state=1)

en_pt_final_en_trainval, en_pt_final_en_test, en_pt_final_pt_trainval, en_pt_final_pt_test = \
    train_test_split(en_pt_final_en, en_pt_final_pt, test_size=test_ratio, random_state=1)

en_pt_final_en_train, en_pt_final_en_val, en_pt_final_pt_train, en_pt_final_pt_val = \
    train_test_split(en_pt_final_en_trainval, en_pt_final_pt_trainval, test_size=validation_ratio, random_state=1)


print("Number of entries in the final Scielo English-Spanish training, validation and test dataset are {}, {} and {}".format(len(en_es_final_en_train),len(en_es_final_en_val),len(en_es_final_en_test)))
print("Number of entries in the final Scielo English-Portugese training, validation and test dataset are {}, {} and {}".format(len(en_pt_final_en_train),len(en_pt_final_en_val),len(en_pt_final_en_test)))
"""
    Write the train, test and val data into files
"""
en_es_final_en_train_filename = "en_es_final_train.en"
en_es_final_en_val_filename = "en_es_final_val.en"
en_es_final_en_test_filename = "en_es_final_test.en"
en_es_final_es_train_filename = "en_es_final_train.es"
en_es_final_es_val_filename = "en_es_final_val.es"
en_es_final_es_test_filename = "en_es_final_test.es"

en_es_final_en_train_filepath = data_dir + "/" + en_es_final_en_train_filename
en_es_final_en_val_filepath = data_dir + "/" + en_es_final_en_val_filename
en_es_final_en_test_filepath = data_dir + "/" + en_es_final_en_test_filename
en_es_final_es_train_filepath = data_dir + "/" + en_es_final_es_train_filename
en_es_final_es_val_filepath = data_dir + "/" + en_es_final_es_val_filename
en_es_final_es_test_filepath = data_dir + "/" + en_es_final_es_test_filename


en_pt_final_en_train_filename = "en_pt_final_train.en"
en_pt_final_en_val_filename = "en_pt_final_val.en"
en_pt_final_en_test_filename = "en_pt_final_test.en"
en_pt_final_pt_train_filename = "en_pt_final_train.pt"
en_pt_final_pt_val_filename = "en_pt_final_val.pt"
en_pt_final_pt_test_filename = "en_pt_final_test.pt"

en_pt_final_en_train_filepath = data_dir + "/" + en_pt_final_en_train_filename
en_pt_final_en_val_filepath = data_dir + "/" + en_pt_final_en_val_filename
en_pt_final_en_test_filepath = data_dir + "/" + en_pt_final_en_test_filename
en_pt_final_pt_train_filepath = data_dir + "/" + en_pt_final_pt_train_filename
en_pt_final_pt_val_filepath = data_dir + "/" + en_pt_final_pt_val_filename
en_pt_final_pt_test_filepath = data_dir + "/" + en_pt_final_pt_test_filename

def write_data_to_file(data, filename):
    f = open(filename, "w")
    for data_entry in data:
        f.write(data_entry)
    f.close()
    
write_data_to_file(en_es_final_en_train, en_es_final_en_train_filepath)
write_data_to_file(en_es_final_en_val, en_es_final_en_val_filepath)
write_data_to_file(en_es_final_en_test, en_es_final_en_test_filepath)
write_data_to_file(en_es_final_es_train, en_es_final_es_train_filepath)
write_data_to_file(en_es_final_es_val, en_es_final_es_val_filepath)
write_data_to_file(en_es_final_es_test, en_es_final_es_test_filepath)  


write_data_to_file(en_pt_final_en_train, en_pt_final_en_train_filepath)
write_data_to_file(en_pt_final_en_val, en_pt_final_en_val_filepath)
write_data_to_file(en_pt_final_en_test, en_pt_final_en_test_filepath)
write_data_to_file(en_pt_final_pt_train, en_pt_final_pt_train_filepath)
write_data_to_file(en_pt_final_pt_val, en_pt_final_pt_val_filepath)
write_data_to_file(en_pt_final_pt_test, en_pt_final_pt_test_filepath)    

步骤 3. 使用 NeMo 微调 NMT 模型。#

NeMo 提供了微调多语言 NMT NeMo 模型所需的微调脚本。 我们可以使用此脚本启动训练。

我们首先从 NGC 下载开箱即用 (OOTB) 的任意语言到英语的多语言 NMT NeMo 模型。 我们将基于 Scielo 数据集微调此模型。

下载模型#

# Create directory to hold model
model_dir = base_dir + "/model"
!mkdir $model_dir

# Download the NMT model from NGC using wget command
!wget -O $model_dir/megatronnmt_any_en_500m_1.0.0.zip --content-disposition https://api.ngc.nvidia.com/v2/models/nvidia/nemo/megatronnmt_any_en_500m/versions/1.0.0/zip 

# Unzip the downloaded model zip file.
!unzip $model_dir/megatronnmt_any_en_500m_1.0.0.zip -d $model_dir/pretrained_ckpt

# Alternate way to download the model from NGC using NGC CLI (Please make sure to install and setup NGC CLI):
#!cd $model_dir && ngc registry model download-version "nvidia/nemo/megatronnmt_any_en_500m:1.0.0"

下载分词器#

tokenizer_dir = base_dir + "/tokenizer"
!mkdir $tokenizer_dir

!wget -O $tokenizer_dir/spm_64k_all_32_langs_plus_en_nomoses.model https://github.com/aishwaryac-nv/tutorials/blob/aishwaryac/add-nmt-tutorials/nmt_configs/spm_64k_all_32_langs_plus_en_nomoses.model

NeMo NMT 微调脚本公开了许多参数

  • trainer.precision:使用的精度类型。 在我们的例子中,它是 bf16

  • trainer.devices:要为微调分配的 GPU 数量。

  • trainer.max_epochs:要运行微调的最大 epoch 数。

  • trainer.max_steps:要运行微调的最大步数。 max_steps 可以覆盖 max_epochs,就像我们在本教程中所做的那样。

  • trainer.val_check_interval:此参数决定在对整个验证数据集运行验证之前要执行的训练步骤数。

  • model.make_vocab_size_divisible_by:在我们的例子中,词汇表大小为 64128。

  • model.pretrained_model_path:本地 OOTB .nemo 模型的路径。

  • model.train_ds.tgt_file_name:训练数据集的目标语言数据文件的路径。 在我们的例子中,这是一个文件列表。

  • model.train_ds.src_file_name:训练数据集的源语言数据文件的路径。 在我们的例子中,这是一个文件列表。

  • model.train_ds.tokens_in_batch:单个训练批次中的 token 数量。 请注意,这不是训练批次中的数据条目数,而是 token 的数量。

  • model.validation_ds.tgt_file_name:验证数据集的目标语言数据文件的路径。 在我们的例子中,这是一个文件列表。

  • model.validation_ds.src_file_name:验证数据集的源语言数据文件的路径。 在我们的例子中,这是一个文件列表。

  • model.test_ds.tgt_file_name:测试数据集的目标语言数据文件的路径(它不接受多个文件,因此实际评估在之后完成)。 在我们的例子中,它将是一个文件,因为此版本尚不支持多个文件。

  • model.test_ds.src_file_name:测试数据集的源语言数据文件的路径(它不接受多个文件,因此实际评估在之后完成)。 在我们的例子中,它将是一个文件,因为此版本尚不支持多个文件。

  • model.encoder_tokenizer.model:分词器模型的路径,在我们的例子中是 - configs/tokenizer/spm_64k_all_32_langs_plus_en_nomoses.model

  • model.decoder_tokenizer.model:分词器模型的路径,在我们的例子中是 - configs/tokenizer/spm_64k_all_32_langs_plus_en_nomoses.model

  • exp_manager.create_wandb_logger:如果使用 wandb,则设置为 true,否则为可选参数。

  • exp_manager.wandb_logger_kwargs.name:如果使用 wandb,则为实验的名称。

  • exp_manager.wandb_logger_kwargs.project:如果使用 wandb,则为项目的名称。

  • exp_manager.resume_if_exists:如果要从某个点继续训练,请将其设置为 true。

  • exp_manager.exp_dir:实验目录的路径,该目录用作 NeMo 微调的工作目录。

  • exp_manager.checkpoint_callback_params.monitor:要监视的指标。 为多种语言添加 val_sacreBLEU_avg(如果在单个语言对(例如 es-en)上进行微调,则添加 val_sacreBLEU_es-en)

  • exp_manager.checkpoint_callback_params.mode:要监视的指标的模式。

  • exp_manager.checkpoint_callback_params.save_top_k

  • exp_manager.checkpoint_callback_params.save_best_model:指示是否必须在每个训练步骤后保存最佳模型的标志。

注意:++model.pretrained_language_list=None:如果您在 en2any 方向进行训练,请删除此项

#Formatting to avoid hydra errors, files expect list of a string as input
train_src_files=[str(en_es_final_es_train_filepath) + ', ' + str(en_pt_final_pt_train_filepath)]
train_tgt_files=[str(en_es_final_en_train_filepath) + ', ' + str(en_pt_final_en_train_filepath)]
val_src_files=[str(en_es_final_es_val_filepath) + ', ' + str(en_pt_final_pt_val_filepath)] 
val_tgt_files=[str(en_es_final_en_val_filepath) + ', ' + str(en_pt_final_en_val_filepath)] 
!HYDRA_FULL_ERROR=1
!python $base_dir/NeMo/examples/nlp/machine_translation/megatron_nmt_training.py \
  trainer.precision=32 \
  trainer.devices=1 \
  trainer.max_epochs=5 \
  trainer.max_steps=200000 \
  trainer.val_check_interval=5000 \
  trainer.log_every_n_steps=5000 \
  ++trainer.replace_sampler_ddp=False \
  model.multilingual=True \
  model.pretrained_model_path=$model_dir/pretrained_ckpt/megatronnmt_any_en_500m.nemo \
  model.micro_batch_size=1 \
  model.global_batch_size=2 \
  model.encoder_tokenizer.library=sentencepiece \
  model.decoder_tokenizer.library=sentencepiece \
  model.encoder_tokenizer.model=$tokenizer_dir/spm_64k_all_32_langs_plus_en_nomoses.model \
  model.decoder_tokenizer.model=$tokenizer_dir/spm_64k_all_32_langs_plus_en_nomoses.model \
  model.src_language=['es, pt'] \
  model.tgt_language=en \
  model.train_ds.src_file_name=$train_src_files \
  model.train_ds.tgt_file_name=$train_tgt_files \
  model.test_ds.src_file_name=$en_es_final_es_test_filepath \
  model.test_ds.tgt_file_name=$en_es_final_en_test_filepath \
  model.validation_ds.src_file_name=$val_src_files \
  model.validation_ds.tgt_file_name=$val_tgt_files \
  model.optim.lr=0.00001 \
  model.train_ds.concat_sampling_probabilities=['0.1, 0.1'] \
  ++model.pretrained_language_list=None \
  +model.optim.sched.warmup_steps=500 \
  ~model.optim.sched.warmup_ratio \
  exp_manager.resume_if_exists=True \
  exp_manager.resume_ignore_no_checkpoint=True \
  exp_manager.create_checkpoint_callback=True \
  exp_manager.checkpoint_callback_params.monitor=val_sacreBLEU_avg \
  exp_manager.checkpoint_callback_params.mode=max \
  exp_manager.checkpoint_callback_params.save_top_k=5 \
  +exp_manager.checkpoint_callback_params.save_best_model=true

步骤 4. 使用 NeMo 评估微调后的 NMT 模型。#

现在我们有了一个微调后的模型,我们需要检查它的性能如何。
我们使用 NeMo 提供的脚本 nmt_transformer_infer_megatron.py,在测试数据集的一个小子集上运行推理,首先使用 OOTB 模型,然后使用微调后的模型。 然后我们比较来自这两个模型的翻译。

NeMo 推理脚本 nmt_transformer_infer_megatron.py 支持多个输入参数,其中最重要的是

  • model:要运行推理的 .nemo 模型的路径

  • srctext:包含要运行推理的换行符分隔的输入样本的文本文件的路径

  • tgtout:要保存翻译的文本文件的路径

  • source_lang:源语言的语言代码。

  • target_lang:目标语言的语言代码。

  • batch_size:推理的批次大小。

  • trainer.precision:模型的精度。 在本节中,我们学习使用此脚本运行推理。

首先,让我们为评估创建一个工作目录。

eval_dir = base_dir + "/eval"
!mkdir $eval_dir

我们选择测试数据的一个小子集进行推理,并将其写入文件。

infer_input_data_en = en_pt_final_en_test[:10]
infer_input_data_pt = en_pt_final_pt_test[:10]

infer_input_data_pt_filename = "infer_input_data_pt.pt"
infer_input_data_pt_filepath = eval_dir + "/" + infer_input_data_pt_filename

f = open(infer_input_data_pt_filepath, "w")
for infer_input_data_pt_entry in infer_input_data_pt:
    f.write(infer_input_data_pt_entry)
f.close()    

让我们在 NeMo NMT OOTB 模型上运行推理。

infer_ootbmodel_output_data_en_filename = "infer_ootbmodel_output_data_en.en"
infer_ootbmodel_output_data_en_filepath = eval_dir + "/" + infer_ootbmodel_output_data_en_filename

!python $base_dir/NeMo/examples/nlp/machine_translation/nmt_transformer_infer_megatron.py \
    model_file=$model_dir/pretrained_ckpt/megatronnmt_any_en_500m.nemo \
    srctext=$infer_input_data_pt_filepath \
    tgtout=$infer_ootbmodel_output_data_en_filepath \
    source_lang=pt \
    target_lang=en \
    batch_size=10 \
    trainer.precision=32

现在我们在 NeMo NMT 微调模型上运行推理。
注意:请务必设置下面的 model 参数,使其指向可以在 $model_dir/results 目录中找到的微调后的 .nemo 检查点。

infer_finetuned_output_data_en_filename = "infer_finetuned_output_data_en.en"
infer_finetuned_output_data_en_filepath = eval_dir + "/" + infer_finetuned_output_data_en_filename

!python $base_dir/NeMo/examples/nlp/machine_translation/nmt_transformer_infer_megatron.py \
    model_file=$model_dir/pretrained_ckpt/megatronnmt_any_en_500m.nemo \
    srctext=$infer_input_data_pt_filepath \
    tgtout=$infer_finetuned_output_data_en_filepath \
    source_lang=pt \
    target_lang=en \
    batch_size=10 \
    trainer.precision=32

让我们显示来自 OOTB 模型和微调模型的翻译,用于我们的推理测试子集。 由于我们仅对 10 个示例执行了评估。 您可以使用 BLEU 分数来评估更大的测试集。

with open(infer_ootbmodel_output_data_en_filepath) as f:
    infer_ootbmodel_output_data_en = f.readlines()

with open(infer_finetuned_output_data_en_filepath) as f:
    infer_finetuned_output_data_en = f.readlines()
    
for infer_input_data_pt_entry, infer_input_data_pt_entry, infer_ootbmodel_output_data_en_entry, infer_finetuned_output_data_en_entry in \
    zip(infer_input_data_pt, infer_input_data_pt, infer_ootbmodel_output_data_en, infer_finetuned_output_data_en):
    print("Portugese: ", infer_input_data_pt_entry)
    print("Portugese-English Translation - Ground Truth: ", infer_input_data_en)
    print("Portugese-English Translation - OOTB model Generated:     ", infer_ootbmodel_output_data_en_entry)
    print("Portugese-English Translation - Finetuned model Generated:", infer_finetuned_output_data_en_entry)
    print("------------------------")

步骤 5. 导出 NeMo 模型#

NeMo 和 Riva 允许您以可以使用 NVIDIA Riva 部署的格式导出微调后的模型; NVIDIA Riva 是一个高性能应用程序框架,适用于使用 GPU 的多模式对话式 AI 服务。

导出到 Riva#

Riva 提供了 nemo2riva 工具,该工具可用于将 .nemo 模型转换为 .riva 模型。 此工具可通过 Riva 快速入门指南获得,并在上面的“要求和设置”步骤中安装。 更新自定义模型的路径,默认情况下它保存为 nemo_experiments/megatron_nmt/checkpoints/megatron_nmt.nemo

!nemo2riva --out $model_dir/megatronnmt_custom_any_en_500m.riva <saved_custom_nemo_model_path>

步骤 6. 在 Riva Speech Skills 服务器上部署微调后的 NeMo NMT 模型。#

NeMo 微调的 NMT 模型需要部署在 Riva Speech Skills 服务器上才能进行推理。
请按照 Riva NMT 教程 中的“如何在 Riva Speech Skills 服务器上部署 NeMo 微调的 NMT 模型?”教程进行操作 - 本 notebook 涵盖了在 Riva Speech Skills 服务器上部署从步骤 5 获取的 .riva 文件。